﻿//动画类，创建时需要tools.js,proto.js模块

if (!window.wkh.classes) {
    window.wkh.classes = {};
}

wkh.classes.Animate = (function () {//动画类
    var pri;
    var defaultStep = 30;//默认间隔
    var defaultProgress = function (p) {
        if (p < 0.5) {
            return 2 * p * p;
        } else {
            var tem = p - 1;
            return -2 * tem * tem + 1;
        }

    };
    var defaultCssFn = function (numArr) {
        return numArr[0].toString();
    };
    var lengthCssFn = function (numArr) {
        return numArr[0] + "px";
    };
    var rgbCssFn = function (numArr) {
        numArr[0] = Math.round(numArr[0]);
        numArr[1] = Math.round(numArr[1]);
        numArr[2] = Math.round(numArr[2]);

        return "rgb(" + numArr.join(",") + ")";
    };

    var rgbaCssFn = function (numArr) {
        numArr[0] = Math.round(numArr[0]);
        numArr[1] = Math.round(numArr[1]);
        numArr[2] = Math.round(numArr[2]);

        return "rgba(" + numArr.join(",") + ")";
    };

    /*说明:   element可以为一个元素或是元素数组(类数组)
              cssRules为元素的css规则
              start和end只能为字符串或为空

              如果要自定义css变化规则，则可使start,end为空，使用animateSelf方法
              该方法start和end可以为数字，或数字数组，cssFn为从自定义数组转化规则
    */
    function classAnimate(element, cssRules, start, end, time, progress) {


        if (!element) {
            return null;
        }

        if (!element.length) {//如果element是一个元素，不是元素数组或类数组
            element = [element];
        }

        var privateVar = {//动画类私有变量
            element: element,//动画元素
            cssRules: wkh.tools.preFixCss(cssRules) || cssRules,//动画规则
            start: (start||"").toString().trim(),//动画开始样式
            end: (end||"").toString().trim(),//动画结事样式

            time: (time || 500).toString().trim(),//动画时间
            progress: progress || defaultProgress,//动画过程
            cssFn: defaultCssFn,

            onstart: [],//正向动画开始
            oncomplete: [],//动画完成后要动行的函数
            onbackcomplete: [],//反向动画完成后要运行的函数
            onbackstart: [],//反向动画开始

            type: "auto",//动画类型：auto,other
            lengthStart: [],//若为opacity,length，开始值（number)
            length: [],//动画样式开始结束差
            nowLength: [],
            nowTime: 0,

            t: 0,//setTimeout的反回值
            step: defaultStep,//设置动画间隔

            //judge: [judgeForward.bind(this), judgeBack.bind(this)],//正向动画和返向动画判断函数
            judgeFn: null,//判断函数
            //doAnimate: [],
            doAnimateFn: doStart.bind(this),//动画循环函数
            isAnimate: false,//动画是否正在进行
            isBack: false//是否反向动行动画
        };

        //如果start和end转为字符串，去掉头尾空格
        this.__wkh_private_getAnimatePrivate = function () {
            pri = privateVar;
        };

        init.call(this);
    }

    function init() {//解析数据
        this.__wkh_private_getAnimatePrivate();

        if (pri.start === "" || pri.end === "") {
            pri.type = "other";
        }

        if (pri.type === "other") {
            return;
        }

        if (startColor = wkh.tools.analyticColor(pri.start)) {//解析颜色
            var startColor;
            var endColor = wkh.tools.analyticColor(pri.end);

            pri.lengthStart = startColor;
            pri.lengthStart[3] = (pri.lengthStart[3] != null ? pri.lengthStart[3] : 1);

            pri.length[0] = endColor[0] - startColor[0];
            pri.length[1] = endColor[1] - startColor[1];
            pri.length[2] = endColor[2] - startColor[2];
            pri.length[3] = (endColor[3] != null ? endColor[3] : 1) - pri.lengthStart[3];

            if (pri.lengthStart[3] === 1 && pri.length[3] === 0) {
                pri.cssFn = rgbCssFn;
                pri.lengthStart.pop();
                pri.length.pop();
            } else {
                pri.cssFn = rgbaCssFn;
            }
        } else {
            pri.lengthStart[0] = parseFloat(pri.start);
            pri.length[0] = parseFloat(pri.end) - pri.lengthStart[0];
            if (pri.start.search(/[pP][xX]/) !== -1) {
                pri.cssFn = lengthCssFn;
            }
        }

        pri.judgeFn = judgeForward;
    }

    classAnimate.prototype.init = function (back) {//初始化动画数据
        this.__wkh_private_getAnimatePrivate();

        if (this.isAnimate()) {
            this.stop();
        }

        if (back) {//反向初始化
            pri.judgeFn = judgeBack;
            pri.isBack = true;
            pri.nowTime = pri.time;

            setElementEnd.call(this);
        } else {
            pri.judgeFn = judgeForward;
            pri.isBack = false;
            pri.nowTime = 0;

            setElementStart.call(this);
        }

        return this;
    };

    function doStart() {
        this.__wkh_private_getAnimatePrivate();

        if (!pri.judgeFn.call(this)) {
            return;
        }

        var position = pri.nowTime / pri.time;
        var LLength = pri.lengthStart.length;
        for (var i = 0; i < LLength; ++i) {
            pri.nowLength[i] = pri.lengthStart[i] + pri.length[i] * pri.progress(position);
        }

        var length = pri.element.length;
        for (var i = 0; i < length; ++i) {
            pri.element[i].css(pri.cssRules, pri.cssFn(pri.nowLength));
        }
    }

    function judgeForward() {//正向动画判断
        if ((pri.nowTime += pri.step) < pri.time) {
            pri.t = setTimeout(pri.doAnimateFn, pri.step);
            return true;
        } else {
            pri.isAnimate = false;
            pri.nowTime = pri.time;
            setElementEnd.call(this);
            runEventHandler.call(this, "complete");
            return false;
        }
    }

    function judgeBack() {//反向判断
        if ((pri.nowTime -= pri.step) > 0) {
            pri.t = setTimeout(pri.doAnimateFn, pri.step);
            return true;
        } else {
            pri.isAnimate = false;
            pri.nowTime = 0;
            setElementStart.call(this);
            runEventHandler.call(this, "backcomplete");
            return false;
        }
    }

    function runEventHandler(type) {//运行事件侦听函数
        this.__wkh_private_getAnimatePrivate();

        type = type || "complete";
        var fn = pri["on" + type];

        var length = fn.length;
        for (var i = 0; i < length; ++i) {
            fn[i].call(this, {
                target: pri.element[0],
                targetList: pri.element,
                type: type,
                animate: this
            });
        }
    }

    function setElementStart() {//将动画元素样式设为初始态
        this.__wkh_private_getAnimatePrivate();
        var length = pri.element.length;

        for (var i = 0; i < length; ++i) {
            pri.element[i].css(pri.cssRules, pri.start);
        }

        return this;
    }

    function setElementEnd() {//将动画元素样式设为结束态
        this.__wkh_private_getAnimatePrivate();
        var length = pri.element.length;

        for (var i = 0; i < length; ++i) {
            pri.element[i].css(pri.cssRules, pri.end);
        }

        return this;
    }

    classAnimate.prototype.animateSelf = function (start, end, cssFn) {//强制转化为自定义css赋值(参数：开始数值，结束值，赋值规则)
        this.__wkh_private_getAnimatePrivate();

        pri.type = "other";
        pri.cssFn = cssFn;
        this.setStart(start, false).setEnd(end);
        pri.doAnimateFn = pri.doAnimate[1];

        return this;
    };

    classAnimate.prototype.doAnimate = function (back/*反向参数，如果为true,则反向运行*/) {//运行动画
        this.__wkh_private_getAnimatePrivate();

        back = back || false;//back默认为false

        if (back === pri.isBack) {//如果正反向相同,跳过
        } else {//否则反向判断
            pri.isBack = back;
            pri.judgeFn = pri.isBack ? judgeBack : judgeForward;
        }

        if (pri.isAnimate === true) {//如果正在动画
        } else {
            pri.isAnimate = true;
            runEventHandler.call(this, pri.isBack ? "backstart" : "start");
            setTimeout(pri.doAnimateFn, pri.step);
        }

        return this;
    };

    classAnimate.prototype.isAnimate = function () {//动画是否正在进行
        this.__wkh_private_getAnimatePrivate();

        return pri.isAnimate;
    };

    classAnimate.prototype.setStart = function (start, isA/*是否解析数据*/) {//设置动画初始值
        this.__wkh_private_getAnimatePrivate();
        if (isA === undefined) {
            isA = true;
        }
        
        if (pri.type === "other") {
            if (start.length != null) {
                pri.lengthStart = start;
            } else {
                pri.lengthStart[0] = parseFloat(start);
            }
            pri.start = pri.cssFn(pri.lengthStart);
        } else {
            pri.start = (start || "").toString().trim();
            if (isA) {
                init.call(this);
            }
        }

        this.init();

        return this;
    };

    classAnimate.prototype.setEnd = function (end, isA/*是否解析数据*/) {//设置结束值
        this.__wkh_private_getAnimatePrivate();
        if (isA === undefined) {
            isA = true;
        }

        if (pri.type === "other") {
            if (end.length != null) {
                var length = end.length;
                for (var i = 0; i < length; ++i) {
                    pri.length[i] = end[i] - pri.lengthStart[i];
                }
            } else {
                end = parseFloat(end);
                pri.length[0] = end - pri.lengthStart[0];
                end = [end];
            }
            pri.end = pri.cssFn(end);
        } else {
            pri.end = (end || "").toString().trim();
            if (isA) {
                init.call(this);
            }
        }

        this.init(true);
        
        return this;
    };

    classAnimate.prototype.setStep = function (step) {//设置步长（动画间隔时间）
        this.__wkh_private_getAnimatePrivate();

        pri.step = step;

        return this;
    };

    classAnimate.prototype.stop = function () {//停止动画
        this.__wkh_private_getAnimatePrivate();
        clearTimeout(pri.t);
        pri.isAnimate = false;

        return this;
    };

    classAnimate.prototype.gotoEnd = function () {//瞬间完成动画
        this.__wkh_private_getAnimatePrivate();

        if (this.isAnimate()) {
            this.init(!pri.isBack);
            runEventHandler.call(this, pri.isBack ? "complete" : "backcomplete");
        }

        return this;
    };

    classAnimate.prototype.changeProgress = function (fn) {
        if (typeof fn != "function") {
            throw new Error("argument is not a funciton");
        }

        this.__wkh_private_getAnimatePrivate();
        pri.progress = fn;

        return this;
    };

    classAnimate.prototype.addEventListener = function (type, fn, isDuplicate) {//添加结束执行函数，第三个参数指定是否可重复添加已有的相同函数
        //事件类型：start complete backstart backcomplete
        this.__wkh_private_getAnimatePrivate();

        if (typeof fn !== "function") {//如果不是函数，返回
            return this;
        }

        var funcs = pri["on" + type.trim().toLowerCase()];

        if (isDuplicate) {
        } else {
            for (var i in funcs) {
                if (funcs[i] === fn) return this;
            }
        }

        funcs.push(fn);
        return this;
    };

    classAnimate.prototype.removeEventListener = function (type, fn, isDuplicate) {//移除结束执行函数，第三个参数指定是否移除所有相同函数
        this.__wkh_private_getAnimatePrivate();
        type = "on" + type.trim().toLowerCase();

        if (!fn) {//如果没有fn参数，去除所有事件侦听器
            pri[type] = [];
            return this;
        }

        if (typeof fn !== "function") {//如果不是函数，返回
            return this;
        }

        var funcs = pri[type];

        for (var i = 0 ; i < funcs.length; ++i) {
            if (funcs[i] === fn) {
                var length = funcs.length;
                for (var j = Number(i) ; j < length - 1; ++j) {
                    funcs[j] = funcs[j + 1];
                }
                funcs.length = length - 1;

                i--;
                if (!isDuplicate) {
                    break;
                }
            }
        }

        return this;
    };

    classAnimate.prototype.className = "Animate";

    classAnimate.setDefaultStep = function (step) {//设置默认间隔，静态函数
        defaultStep = step;
    };

    classAnimate.setDefaultProgress = function (fn) {//设置默认过程函数
        if (typeof fn !== "function") {
            throw new Error("Animate.setDefaultProgress的参数不是函数");
        }

        defaultProgress = fn;
    };

    classAnimate.__wkh_private_className = "Animate";

    return classAnimate;
}());

wkh.classes.Animates = (function () {
    var pri;

    function classAnimates(element,cssR, time, progress) {
        var privateVar = [];
        privateVar.element = element;
        privateVar.time = time;
        privateVar.progress = progress;

        for (var css in cssR) {
            var value = cssR[css];
            privateVar.push(new wkh.classes.Animate(element, css, value[0], value[1], time, progress));
        }

        this.__wkh_private_getAnimatesPrivate = function () {
            pri = privateVar;
        };
    }

    classAnimates.prototype.init = function (back) {
        this.__wkh_private_getAnimatesPrivate();

        for (var i = 0; i < pri.length; ++i) {
            pri[i].init(back);
        }

        return this;
    };

    classAnimates.prototype.isAnimate = function () {//动画是否正在进行
        this.__wkh_private_getAnimatesPrivate();

        var is = false;
        for (var i = 0; i < pri.length; ++i) {
            is = pri[i].isAnimate();
            if (is) {
                break;
            }
        }

        return is;
    };

    classAnimates.prototype.doAnimate = function (back) {
        this.__wkh_private_getAnimatesPrivate();

        for (var i = 0; i < pri.length; ++i) {
            pri[i].doAnimate(back);
        }

        return this;
    };

    classAnimates.prototype.setStep = function (step) {//设置步长（动画间隔时间）
        this.__wkh_private_getAnimatesPrivate();

        for (var i = 0; i < pri.length; ++i) {
            pri[i].setStep(step);
        }

        return this;
    };

    classAnimates.prototype.stop = function () {//停止动画
        this.__wkh_private_getAnimatesPrivate();

        for (var i = 0; i < pri.length; ++i) {
            pri[i].stop();
        }

        return this;
    };

    classAnimates.prototype.gotoEnd = function () {//瞬间完成动画
        this.__wkh_private_getAnimatesPrivate();

        for (var i = 0; i < pri.length; ++i) {
            pri[i].gotoEnd();
        }

        return this;
    };

    classAnimates.prototype.addEventListener = function (type, fn, isDuplicate) {
        this.__wkh_private_getAnimatesPrivate();

        pri[pri.length - 1].addEventListener(type, fn, isDuplicate);

        return this;
    };

    classAnimates.prototype.removeEventListener = function (type, fn, isDuplicate) {
        this.__wkh_private_getAnimatesPrivate();

        pri[pri.length - 1].removeEventListener(type, fn, isDuplicate);

        return this;
    };

    classAnimates.prototype.add = function (css, start, end, cssFn) {
        this.__wkh_private_getAnimatesPrivate();

        var ani = new wkh.classes.Animate(pri.element, css, null, null, pri.time, pri.progress);
        ani.animateSelf(start, end, cssFn);
        pri.push(ani);

        return this;
    };

    classAnimates.prototype.className = "Animates";

    classAnimates.__wkh_private_className = "Animates";

    return classAnimates;
}());

wkh.classes.AnimateList = (function () {
    var pri;

    function classAnimateList() {
        var privateVar = [];

        this.__wkh_private_getAnimateListPrivate = function () {
            pri = privateVar;
        }
    }

    function add(a) {//内部使用,添加一个动画对象
        if (a.className && (a.className === "Animate" || a.className === "Animates")) {
            pri.push(a);
        }
    }

    function remove(a) {//移除一个动画对象
        pri.remove(a);
    }

    classAnimateList.prototype.add = function (a) {//外部使用，添加一组动画对象
        this.__wkh_private_getAnimateListPrivate();

        if (a.length != undefined) {
            Array.prototype.forEach.call(pri, function (val) {
                add(val);
            });
        } else {
            add(a);
        }

        return this;
    };

    classAnimateList.prototype.remove = function (a) {//移除一组动画对象
        this.__wkh_private_getAnimateListPrivate();

        if (a.length !== undefined) {
            Array.prototype.forEach.call(pri, function (val) {
                remove(val);
            });
        } else {
            remove(val);
        }

        return this;
    };

    classAnimateList.prototype.init = function (back) {
        this.__wkh_private_getAnimateListPrivate();
        pri.forEach(function (val) {
            val.init(back);
        });

        return this;
    };

    classAnimateList.prototype.isAnimate = function () {
        this.__wkh_private_getAnimateListPrivate();

        var is = false;
        for (var i = 0; i < pri.length; ++i) {
            is = pri[i].isAnimate();
            if (is) {
                break;
            }
        }

        return is;
    };

    classAnimateList.prototype.doAnimate = function () {
        this.__wkh_private_getAnimateListPrivate();
        pri.forEach(function (val) {
            val.doAnimate();
        });
        return this;
    };

    classAnimateList.prototype.stop = function () {
        this.__wkh_private_getAnimateListPrivate();

        pri.forEach(function (val) {
            val.stop();
        });

        return this;
    };

    classAnimateList.prototype.gotoEnd = function () {
        this.__wkh_private_getAnimateListPrivate();

        pri.forEach(function (val) {
            val.gotoEnd();
        });

        return this;
    };

    classAnimateList.prototype.className = "AnimateList";

    classAnimateList.__wkh_private_className = "AnimateList";

    return classAnimateList;
}());
